import { history } from '@umijs/max';
import { extend, RequestOptionsInit } from 'umi-request';
import storage from './store';

// 类型定义
export interface ApiResponse<T = any> {
  code: number;
  msg: string;
  data?: T;
  stacktrace?: string | null;
}

export interface RequestConfig {
  timeout?: number;
  retryCount?: number;
  retryDelay?: number;
  showLoading?: boolean;
  showError?: boolean;
}

export interface RequestOptions extends RequestOptionsInit {
  config?: RequestConfig;
}

export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';

// 常量配置
const LOGIN_PATH = '/user/login';
const API_HOST = '/api';
const DEFAULT_TIMEOUT = 600 * 1000; // 10分钟
const DEFAULT_RETRY_COUNT = 3;
const DEFAULT_RETRY_DELAY = 1000; // 1秒

// 错误码映射
const CODE_MESSAGE: Record<number, string> = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '用户得到授权，但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
};

// Token 相关错误码
const TOKEN_MESSAGE: Record<number, string> = {
  11012: '登录信息已过期，请重新登录',
  11014: '您的账户已在另一台设备上登录，如非本人操作，请立即修改密码',
};

/**
 * 处理认证错误
 */
const handleAuthError = (): void => {
  localStorage.clear();
  sessionStorage.clear();
  // 可以在这里添加消息提示
  // message.warn({ message: '登录失效，即将重新登录！' });
};

/**
 * 工具函数：延迟执行
 */
const delay = (ms: number): Promise<void> => new Promise<void>(resolve => {
  setTimeout(() => resolve(), ms);
});

/**
 * 工具函数：检查是否为网络错误
 */
const isNetworkError = (error: any): boolean => {
  return !error.response && (error.code === 'NETWORK_ERROR' || error.message?.includes('Network Error'));
};

/**
 * 工具函数：检查是否为超时错误
 */
const isTimeoutError = (error: any): boolean => {
  return error.code === 'TIMEOUT' || error.message?.includes('timeout');
};

/**
 * 工具函数：检查是否应该重试
 */
const shouldRetry = (error: any, retryCount: number, maxRetries: number): boolean => {
  if (retryCount >= maxRetries) return false;
  if (error.response?.status >= 400 && error.response?.status < 500) return false;
  return isNetworkError(error) || isTimeoutError(error) || error.response?.status >= 500;
};

/**
 * 增强的异常处理程序
 */
const errorHandler = (error: { response?: Response; code?: string; message?: string }): ApiResponse => {
  const { response } = error;
  
  if (response && response.status) {
    const errorText = CODE_MESSAGE[response.status] || response.statusText;
    const { status } = response;

    // 处理认证相关错误
    if (status === 401) {
      handleAuthError();
      return {
        code: status,
        msg: '登录信息已过期，请重新登录',
        stacktrace: null,
      };
    }

    return {
      code: status,
      msg: errorText,
      stacktrace: null,
    };
  } 
  
  // 处理网络错误
  if (isNetworkError(error)) {
    return {
      code: 504,
      msg: '网络连接异常，请检查网络设置',
      stacktrace: null,
    };
  }

  // 处理超时错误
  if (isTimeoutError(error)) {
    return {
      code: 504,
      msg: '请求超时，请稍后重试',
      stacktrace: null,
    };
  }

  return {
    code: 500,
    msg: error.message || '未知错误',
    stacktrace: null,
  };
};

/**
 * 生成请求ID
 */
const generateRequestId = (): string => {
  return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
};

/**
 * 创建请求实例
 */
const request = extend({
  timeout: DEFAULT_TIMEOUT,
  errorHandler,
});

/**
 * 请求拦截器
 */
request.interceptors.request.use((url: string, options: RequestOptions) => {
  const token = storage.getLocal('token');
  const config = options.config || {};
  
  // 构建请求头
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.headers as Record<string, string>),
  };

  // 添加认证头（除了认证相关的接口）
  if (token && !url.includes('auth')) {
    headers.Authorization = `Bearer ${token}`;
  }

  // 添加请求ID用于追踪
  headers['X-Request-ID'] = generateRequestId();

  return {
    url,
    options: {
      ...options,
      headers,
      timeout: config.timeout || DEFAULT_TIMEOUT,
    },
  };
});

/**
 * 响应拦截器
 */
request.interceptors.response.use(async (response: any) => {
  const { status } = response;

  // 更新token
  if (response.headers.get('authorization')) {
    storage.setLocal('token', response.headers.get('authorization'));
    sessionStorage.setItem('isLogin', 'true');
  }

  // 处理特殊状态码
  if (status === 504) {
    const errorText = TOKEN_MESSAGE[response?.data?.code] || '登录信息已过期，请重新登录';
    handleAuthError();
    history.push(LOGIN_PATH);
    return {
      code: 504,
      msg: errorText,
      stacktrace: null,
    };
  }

  return response;
});

/**
 * 带重试机制的请求执行器
 */
const executeWithRetry = async <T>(
  requestFn: () => Promise<T>,
  config: RequestConfig = {}
): Promise<T> => {
  const { retryCount = DEFAULT_RETRY_COUNT, retryDelay = DEFAULT_RETRY_DELAY } = config;
  let lastError: any;

  for (let i = 0; i <= retryCount; i++) {
    try {
      return await requestFn();
    } catch (error) {
      lastError = error;
      
      if (i < retryCount && shouldRetry(error, i, retryCount)) {
        await delay(retryDelay * (i + 1)); // 指数退避
        continue;
      }
      
      throw error;
    }
  }
  
  throw lastError;
};

/**
 * 基础请求方法
 */
const baseRequest = async <T = any>(
  url: string,
  method: HttpMethod,
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  const { config = {}, ...requestOptions } = options;
  
  const requestFn = () => request(API_HOST + url, {
    method,
    ...requestOptions,
  });

  return executeWithRetry(requestFn, config);
};

/**
 * GET 请求
 * @param url 请求路径
 * @param params 查询参数
 * @param options 请求选项
 */
export const getData = async <T = any>(
  url: string, 
  params?: Record<string, any>, 
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'GET', {
    ...options,
    params,
  });
};

/**
 * POST 请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param params 查询参数
 * @param options 请求选项
 */
export const postData = async <T = any>(
  url: string, 
  data?: Record<string, any>, 
  params?: Record<string, any>,
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'POST', {
    ...options,
    data,
    params,
  });
};

/**
 * PUT 请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param params 查询参数
 * @param options 请求选项
 */
export const putData = async <T = any>(
  url: string, 
  data?: Record<string, any>, 
  params?: Record<string, any>,
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'PUT', {
    ...options,
    data,
    params,
  });
};

/**
 * PATCH 请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param params 查询参数
 * @param options 请求选项
 */
export const patchData = async <T = any>(
  url: string, 
  data?: Record<string, any>, 
  params?: Record<string, any>,
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'PATCH', {
    ...options,
    data,
    params,
  });
};

/**
 * DELETE 请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param params 查询参数
 * @param options 请求选项
 */
export const deleteData = async <T = any>(
  url: string, 
  data?: Record<string, any>, 
  params?: Record<string, any>,
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'DELETE', {
    ...options,
    data,
    params,
  });
};

/**
 * 文件上传请求
 * @param url 请求路径
 * @param data 表单数据
 * @param options 请求选项
 */
export const postFile = async <T = any>(
  url: string, 
  data: FormData | Record<string, any>, 
  options: RequestOptions = {}
): Promise<ApiResponse<T>> => {
  return baseRequest<T>(url, 'POST', {
    ...options,
    data,
    requestType: 'form',
  });
};

/**
 * 文件下载请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param options 请求选项
 */
export const download = async (
  url: string, 
  data?: Record<string, any>,
  options: RequestOptions = {}
): Promise<Blob | ApiResponse> => {
  const result = await baseRequest(url, 'POST', {
    ...options,
    data,
    responseType: 'blob',
  });

  // 检查是否为错误响应
  if (result && typeof result === 'object' && 'type' in result && result.type === 'application/json') {
    return {
      code: 500,
      msg: '下载失败，请稍后再试！',
      stacktrace: null,
    };
  }

  return result as unknown as Blob;
};

/**
 * 批量请求
 * @param requests 请求数组
 */
export const batchRequest = async <T = any>(
  requests: Array<() => Promise<ApiResponse<T>>>
): Promise<ApiResponse<T>[]> => {
  return Promise.all(requests.map(request => request()));
};

/**
 * 并发请求（限制并发数）
 * @param requests 请求数组
 * @param concurrency 并发数限制
 */
export const concurrentRequest = async <T = any>(
  requests: Array<() => Promise<ApiResponse<T>>>,
  concurrency: number = 5
): Promise<ApiResponse<T>[]> => {
  const results: ApiResponse<T>[] = [];
  const executing: Promise<void>[] = [];

  for (const request of requests) {
    const promise = request().then(result => {
      results.push(result);
    });

    executing.push(promise);

    if (executing.length >= concurrency) {
      await Promise.race(executing);
      executing.splice(executing.findIndex(p => p === promise), 1);
    }
  }

  await Promise.all(executing);
  return results;
};

/**
 * 实用工具函数
 */

/**
 * 检查响应是否成功
 * @param response API响应
 */
export const isSuccess = (response: ApiResponse): boolean => {
  return response.code === 200 || response.code === 201;
};

/**
 * 检查响应是否为错误
 * @param response API响应
 */
export const isError = (response: ApiResponse): boolean => {
  return !isSuccess(response);
};

/**
 * 从响应中提取数据
 * @param response API响应
 */
export const extractData = <T>(response: ApiResponse<T>): T | null => {
  return isSuccess(response) ? response.data || null : null;
};

/**
 * 从响应中提取错误信息
 * @param response API响应
 */
export const extractError = (response: ApiResponse): string => {
  return isError(response) ? response.msg : '';
};

/**
 * 创建请求配置
 * @param config 配置选项
 */
export const createRequestConfig = (config: Partial<RequestConfig> = {}): RequestConfig => {
  return {
    timeout: DEFAULT_TIMEOUT,
    retryCount: DEFAULT_RETRY_COUNT,
    retryDelay: DEFAULT_RETRY_DELAY,
    showLoading: true,
    showError: true,
    ...config,
  };
};

/**
 * 创建请求选项
 * @param options 选项
 */
export const createRequestOptions = (options: Partial<RequestOptions> = {}): RequestOptions => {
  return {
    config: createRequestConfig(),
    ...options,
  };
};

/**
 * 请求取消控制器
 */
export class RequestController {
  private controllers: Map<string, AbortController> = new Map();

  /**
   * 创建请求控制器
   * @param requestId 请求ID
   */
  create(requestId: string): AbortController {
    const controller = new AbortController();
    this.controllers.set(requestId, controller);
    return controller;
  }

  /**
   * 取消请求
   * @param requestId 请求ID
   */
  cancel(requestId: string): void {
    const controller = this.controllers.get(requestId);
    if (controller) {
      controller.abort();
      this.controllers.delete(requestId);
    }
  }

  /**
   * 取消所有请求
   */
  cancelAll(): void {
    this.controllers.forEach(controller => controller.abort());
    this.controllers.clear();
  }

  /**
   * 获取控制器
   * @param requestId 请求ID
   */
  getController(requestId: string): AbortController | undefined {
    return this.controllers.get(requestId);
  }
}

/**
 * 全局请求控制器实例
 */
export const requestController = new RequestController();

/**
 * 请求缓存管理
 */
export class RequestCache {
  private cache: Map<string, { data: any; timestamp: number; ttl: number }> = new Map();

  /**
   * 设置缓存
   * @param key 缓存键
   * @param data 缓存数据
   * @param ttl 生存时间（毫秒）
   */
  set(key: string, data: any, ttl: number = 5 * 60 * 1000): void {
    this.cache.set(key, {
      data,
      timestamp: Date.now(),
      ttl,
    });
  }

  /**
   * 获取缓存
   * @param key 缓存键
   */
  get(key: string): any | null {
    const item = this.cache.get(key);
    if (!item) return null;

    if (Date.now() - item.timestamp > item.ttl) {
      this.cache.delete(key);
      return null;
    }

    return item.data;
  }

  /**
   * 删除缓存
   * @param key 缓存键
   */
  delete(key: string): void {
    this.cache.delete(key);
  }

  /**
   * 清空缓存
   */
  clear(): void {
    this.cache.clear();
  }

  /**
   * 清理过期缓存
   */
  cleanup(): void {
    const now = Date.now();
    for (const [key, item] of this.cache.entries()) {
      if (now - item.timestamp > item.ttl) {
        this.cache.delete(key);
      }
    }
  }
}

/**
 * 全局请求缓存实例
 */
export const requestCache = new RequestCache();

/**
 * 带缓存的请求
 * @param cacheKey 缓存键
 * @param requestFn 请求函数
 * @param ttl 缓存时间（毫秒）
 */
export const cachedRequest = async <T>(
  cacheKey: string,
  requestFn: () => Promise<ApiResponse<T>>,
  ttl: number = 5 * 60 * 1000
): Promise<ApiResponse<T>> => {
  // 尝试从缓存获取
  const cached = requestCache.get(cacheKey);
  if (cached) {
    return cached;
  }

  // 执行请求
  const result = await requestFn();
  
  // 只有成功时才缓存
  if (isSuccess(result)) {
    requestCache.set(cacheKey, result, ttl);
  }

  return result;
};

/**
 * 请求统计
 */
export class RequestStats {
  private stats = {
    total: 0,
    success: 0,
    error: 0,
    avgResponseTime: 0,
    responseTimes: [] as number[],
  };

  /**
   * 记录请求
   * @param responseTime 响应时间
   * @param success 是否成功
   */
  record(responseTime: number, success: boolean): void {
    this.stats.total++;
    if (success) {
      this.stats.success++;
    } else {
      this.stats.error++;
    }
    
    this.stats.responseTimes.push(responseTime);
    this.stats.avgResponseTime = this.stats.responseTimes.reduce((a, b) => a + b, 0) / this.stats.responseTimes.length;
  }

  /**
   * 获取统计信息
   */
  getStats() {
    return { ...this.stats };
  }

  /**
   * 重置统计
   */
  reset(): void {
    this.stats = {
      total: 0,
      success: 0,
      error: 0,
      avgResponseTime: 0,
      responseTimes: [],
    };
  }
}

/**
 * 全局请求统计实例
 */
export const requestStats = new RequestStats();

/**
 * 默认导出所有请求方法
 */
export default {
  getData,
  postData,
  putData,
  patchData,
  deleteData,
  postFile,
  download,
  batchRequest,
  concurrentRequest,
  cachedRequest,
  isSuccess,
  isError,
  extractData,
  extractError,
  createRequestConfig,
  createRequestOptions,
  requestController,
  requestCache,
  requestStats,
};
